package com.demo.ipcSocket;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.management.ThreadInfo;
import java.net.Socket;


/**
 * @author MT
 * @date 2019-12-09 13:17
 */
@Slf4j
public class SocketHandler {
    /**
     * 将连接的Socket注册到Socket池中
     *
     * @param socket
     * @return
     */
    public static ClientSocket register(Socket socket) {
        try {
            ClientSocket clientSocket = new ClientSocket();
            clientSocket.setSocket(socket);
            log.info("消息链接" + socket.toString());
            clientSocket.setInputStream(new DataInputStream(socket.getInputStream()));
            clientSocket.setOutputStream(new DataOutputStream(socket.getOutputStream()));
            byte[] bytes = new byte[socket.getReceiveBufferSize()];
            int len = clientSocket.getInputStream().read(bytes);
            log.info("档次接受整体消息长度:" + len);
            //去除4是因为0xFF是起始码1位版本号所以从4开始获取数据
            log.info("接受本次消息长度:" + len);
            log.info("接受本次消息长度0:" + (bytes[0] & 0xFF));
            int mssageHeader = (bytes[0] & 0xFF);
            if (mssageHeader == 255) {
                log.info("接受本次消息长度1:" + (bytes[1] & 0xFF));
                byte[] dataLenBytes = new byte[4];
                dataLenBytes[0] = bytes[2];
                dataLenBytes[1] = bytes[3];
                dataLenBytes[2] = bytes[4];
                dataLenBytes[3] = bytes[5];
                int dataLen = byte2int(dataLenBytes);
                log.info("接受整体消息长度toint:" + dataLen);
                log.info("接受整体消息长度toint:" + byteArrayToInt(dataLenBytes));
                log.info("接受整体消息:" + new String(bytes, 6, dataLen));
                clientSocket.setKey(new String(bytes, 6, dataLen, "UTF-8"));
                SocketPool.add(clientSocket);
            }
            return clientSocket;
        } catch (Exception e) {
            log.error("消息错误", e);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 向指定客户端发送信息
     *
     * @param clientSocket
     * @param message
     */
    public static void sendMessage(ClientSocket clientSocket, String message) {
        try {
            log.info("向指定客户端发送信息-开始");
            log.info("clientSocket={}", JSON.toJSONString(clientSocket));
            log.info("message={}", message);
            byte[] messageData = new byte[message.getBytes("utf-8").length];
            messageData = message.getBytes("utf-8");
            //消息头组装
            byte[] messageHead = new byte[6];
            messageHead[0] = (byte) (0xff);//起始位
            messageHead[1] = (byte) (1);//版本号8位
            int len = messageData.length;
            //数据长度32位
            messageHead[2] = (byte) (len & 0xff);
            messageHead[3] = (byte) (len >> 8 & 0xff);
            messageHead[4] = (byte) (len >> 16 & 0xff);
            messageHead[5] = (byte) (len >> 24 & 0xff);

            byte[] messageSocket = new byte[6 + len];
            //合并消息头和消息体
            System.arraycopy(messageHead, 0, messageSocket, 0, 6);
            System.arraycopy(messageData, 0, messageSocket, 6, len);
            clientSocket.getOutputStream().write(messageSocket);
            log.info("向指定客户端发送信息-结束");
        } catch (Exception e) {
            log.error("发送信息异常：{}", e);
            SocketHandler.close(clientSocket);
        }
    }

    /**
     * 获取指定客户端的上传信息
     *
     * @param clientSocket
     * @return
     */
    public static String onMessage(ClientSocket clientSocket) {
        byte[] bytes = new byte[1024];
        try {
            clientSocket.getInputStream().read(bytes);
            String msg = new String(bytes, "utf-8");
            return msg;
        } catch (IOException e) {
            log.error("接收信息异常：{}", e);
            e.printStackTrace();
            SocketHandler.close(clientSocket);
        }
        return null;
    }

    /**
     * 指定Socket资源回收
     *
     * @param clientSocket
     */
    public static void close(ClientSocket clientSocket) {
        //log.info("进行资源回收");
        if (clientSocket != null) {
            //log.info("开始回收socket相关资源，其Key为{}", clientSocket.getKey());
            SocketPool.remove(clientSocket.getKey());
            Socket socket = clientSocket.getSocket();
            try {
                if (!clientSocket.isCloseStream()) {
                    socket.shutdownInput();
                    socket.shutdownOutput();
                }
            } catch (IOException e) {
                log.error("关闭输入输出流异常，{}", e);
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    log.error("关闭socket异常{}", e);
                }
            }
        }
    }


    /**
     * 发送数据包，判断数据连接状态
     *
     * @param clientSocket
     * @return
     */
    public static boolean isSocketClosed(ClientSocket clientSocket) {
        try {
            clientSocket.getSocket().sendUrgentData(1);
            return false;
        } catch (IOException e) {
            return true;
        }
    }

    //byte 数组与 int 的相互转换
    public static int byteArrayToInt(byte[] b) {
        return b[3] & 0xFF |
                (b[2] & 0xFF) << 8 |
                (b[1] & 0xFF) << 16 |
                (b[0] & 0xFF) << 24;
    }

    public static int byte2int(byte[] b) {
        int res = 0;
        int bLen = b.length;

        if (bLen < 5) {// int 最大到4个字节
            for (int i = 0; i < bLen; i++) {
                res += (b[i] & 0xFF) << (8 * i);
            }
        }

        return res;

    }

    /**
     * 数组BE转int
     *
     * @param bytes 数组大端BE
     * @return int
     */
    private static int byteBE2Int(byte[] bytes) {

        int addr;
        if (bytes.length == 1) {
            addr = bytes[0] & 0xFF;
        } else {
            addr = bytes[0] & 0xFF;
            addr = (addr << 8) | (bytes[1] & 0xff);
            addr = (addr << 8) | (bytes[2] & 0xff);
            addr = (addr << 8) | (bytes[3] & 0xff);
        }
        return addr;
    }
}
